package com.hopes.bizz.close.position.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.map.MapUtil;
import cn.hutool.core.util.ObjUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hopes.bizz.close.common.constant.CacheConstants;
import com.hopes.bizz.close.position.dto.HazardCachePositionDTO;
import com.hopes.bizz.close.position.dto.HazardCarDTO;
import com.hopes.bizz.close.position.service.HazardCachePositionService;
import com.hopes.bizz.close.position.support.impl.RedisHazardRtPositionHandle;
import com.hopes.bizz.close.position.vo.HazardCachePositionVO;
import com.hopes.bizz.close.position.vo.HazardCarTotalOnlineVO;
import com.hopes.bizz.close.visitor.entity.ClosedHazardCarApplyEntity;
import com.hopes.bizz.close.visitor.service.ClosedHazardCarApplyService;
import com.hopes.boss.common.core.util.R;
import com.hopes.boss.common.data.resolver.TenantKeyStrResolver;
import com.hopes.boss.common.security.util.SecurityUtils;
import lombok.RequiredArgsConstructor;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author yumr
 * @ProjectName bizz
 * @Description 危险品车辆实时定位
 * @time 2024/1/30 14:30
 */
@Service
@RequiredArgsConstructor
public class HazardCachePositionServiceImpl implements HazardCachePositionService {

    private final StringRedisTemplate stringRedisTemplate;
    private final TenantKeyStrResolver tenantKeyStrResolver;
    private final RedisTemplate<String, Object> redisTemplate;
    private final ClosedHazardCarApplyService closedHazardCarApplyService;

    @Override
    public R locations(HazardCachePositionDTO hazardCachePositionDTO) {
        final String str = JSONUtil.toJsonStr(hazardCachePositionDTO);
        stringRedisTemplate.convertAndSend(RedisHazardRtPositionHandle.CHANNEL, str);
        return R.ok();
    }

    @Override
    @CacheEvict(value = {CacheConstants.CLOSE_GPS_DEVICE, CacheConstants.CLOSE_HAZARD_CACHE_POSITION}, allEntries = true)
    public boolean cleanHazardCarCachePosition() {
        final String cachePositionKey = String.format("%s:%s::*", tenantKeyStrResolver.key(), CacheConstants.CLOSE_HAZARD_CACHE_POSITION);
        final Set<String> keys = redisTemplate.keys(cachePositionKey);
        if (CollUtil.isEmpty(keys)) {
            return false;
        }
        return Optional.ofNullable(redisTemplate.delete(keys)).orElse(0L) > 0;
    }

    @Override
    public List<HazardCachePositionVO> listHazardCarCachePosition() {
        final String cachePositionKey = String.format("%s:%s::*", tenantKeyStrResolver.key(), CacheConstants.CLOSE_HAZARD_CACHE_POSITION);
        final Set<String> keys = redisTemplate.keys(cachePositionKey);
        if (CollUtil.isEmpty(keys)) {
            return new ArrayList<>();
        }
        final List<Object> cachePositionList = redisTemplate.opsForValue().multiGet(keys);
        if (CollUtil.isEmpty(cachePositionList)) {
            return new ArrayList<>();
        }
        return cachePositionList.stream().map(e -> (HazardCachePositionVO)e).collect(Collectors.toList());
    }

    @Override
    public IPage<HazardCarTotalOnlineVO> pageTotalOnlineNumber(Page page) {
        // 1、绑定了GPS设备的危险品车辆预约
        final Map<Long, Long> orgIdTotalMap = closedHazardCarApplyService.queryBindGpsDeviceList().parallelStream().filter(e ->
                ObjUtil.isNotNull(e.getOrgId())).collect(Collectors.groupingBy(ClosedHazardCarApplyEntity::getOrgId, Collectors.counting()));

        // 2、查询在线的数据
        final Map<String, Long> orgIdOnlineMap = this.listHazardCarCachePosition().parallelStream().filter(e ->
                ObjUtil.isNotNull(e.getOrgId())).collect(Collectors.groupingBy(HazardCachePositionVO::getOrgId, Collectors.counting()));

        final List<HazardCarTotalOnlineVO> hazardCachePositionList = orgIdTotalMap.entrySet().stream().map(e -> {
            final Long orgId = e.getKey();
            final int totalNum = e.getValue().intValue();
            final Integer onlineNum = MapUtil.getInt(orgIdOnlineMap, orgId.toString(), 0);
            return new HazardCarTotalOnlineVO(orgId, totalNum, onlineNum);
        }).collect(Collectors.toList());

        final Page<HazardCarTotalOnlineVO> res = new Page<>(page.getCurrent(), page.getSize(), hazardCachePositionList.size());
        res.setRecords(hazardCachePositionList);
        return res;
    }

    @Override
    public List<HazardCachePositionVO> listHazardCarRtPosition(HazardCarDTO hazardCarDTO) {
        final List<HazardCachePositionVO> hazardCachePositionList = this.listHazardCarCachePosition();
        // 企业人员
        if (SecurityUtils.isCompany() && ObjUtil.isNotNull(SecurityUtils.getOrgId())) {
            hazardCachePositionList.removeIf(next ->
                    !SecurityUtils.getOrgId().toString().equals(next.getOrgId())
                            || (StrUtil.isNotEmpty(hazardCarDTO.getDeviceNo()) && !hazardCarDTO.getDeviceNo().equals(next.getDeviceNo())));
        } else {
            // 园区、管理账号
            hazardCachePositionList.removeIf(next ->
                    ObjUtil.isNull(next.getOrgId())
                            || (StrUtil.isNotEmpty(hazardCarDTO.getOrgIds()) && !hazardCarDTO.getOrgIds().contains(next.getOrgId().toString()))
                            || (StrUtil.isNotEmpty(hazardCarDTO.getDeviceNo()) && !hazardCarDTO.getDeviceNo().equals(next.getDeviceNo())));
        }
        if (StrUtil.isNotBlank(hazardCarDTO.getKeyword())) {
            hazardCachePositionList.removeIf(next -> !next.getLicencePlateNum().contains(hazardCarDTO.getKeyword()) && !next.getBillNo().contains(hazardCarDTO.getKeyword()));
        }
        return hazardCachePositionList;
    }

    @Override
    public IPage<HazardCachePositionVO> pageHazardCarRtPosition(Page page, HazardCarDTO hazardCarDTO) {
        final List<HazardCachePositionVO> hazardCachePositionList = this.listHazardCarRtPosition(hazardCarDTO);
        final Page<HazardCachePositionVO> res = new Page<>(page.getCurrent(), page.getSize(), hazardCachePositionList.size());
        res.setRecords(hazardCachePositionList);
        return res;
    }
}
